package com.example.demo.designMode.singleton;
/**
* @description: TODO 懒汉模式-双检锁
* @author 杨镇宇
* @date 2022/2/28 15:08
* @version 1.0
*/

public class LanSingletonTest {
    public static void main(String[] args) {
        new Thread(()->{
            System.out.println(LanSingleton.getInstance());
        }).start();
        new Thread(()->{
            System.out.println(LanSingleton.getInstance());

        }).start();
    }

}
/**
 * 1、构造函数私有化--防止外面直接调用
 * 2、制作一个返回单例方法
 * 3、实现一个单例类对象 ，并在前面加上volatile
 * 4、判断-如果该单例对象为空，实例化一个对象(第一次检查)
 * 5、为了防止多线程场景下多个线程同时访问，多次初始化单例类对象，初始化实例对象前加一把锁
 * 6、为了防止多线程场景下多个线程第一个检查校验过去，走下面的锁竞争后，依次创建实例，违反单例原则
 *    在加一次检查，只有为空的时候场景单例对象(第二次检查)
 * 7、!= null 直接返回
 * 8、这就是饿汉模式-双检锁
 *
 * 问:为什么不在方法上加锁，而是在方法内部加锁?
 *  因为直接在方法上加锁，相当于每次线程调用过来都要等上一个线程执行完毕，实际消耗时间太大。
 * 问:现一个单例类对象前面为什么要加volatile 关键字
 * JVM加载会有重排序的问题，因为CPU为了加载执行速度，会根据自己的优化策略，有些代码会进行优化，即重排序，
 * 而volatile有防止重排序的特点
 * */
class LanSingleton{
    private volatile static LanSingleton instance;
    //
    private LanSingleton(){}

    public static LanSingleton getInstance(){
        if (instance == null){
            synchronized (LanSingleton.class){
                if (instance == null){
                    instance = new LanSingleton();
                }
            }
        }
        return instance;
    }

}